package com.scut.dispatching_server.scheduler;

import com.alibaba.fastjson.JSONObject;
import com.scut.dispatching_server.config.GlobalVariables;
import com.scut.dispatching_server.endpoint.SupplierEndpoint;
import com.scut.dispatching_server.model.DemandDispatchingInfo;
import com.scut.dispatching_server.service.*;
import com.scut.dispatching_server.tool.DispatchingMatrixTool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import javax.websocket.Session;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

@Configuration      //1.主要用于标记配置类，兼备Component的效果。
@EnableScheduling   // 2.开启定时任务
public class Dispatching {

    @Autowired
    private DispatchingService dispatchingService;
    @Autowired
    private DemandCache demandCache;
    @Autowired
    private SupplierCache supplierCache;
    @Autowired
    private RelationshipPost relationshipPost;

    @Autowired
    private RelationshipCache relationshipCache;

    @Autowired
    private StatisticsService statisticsService;

    private static final Logger sysLogger = Logger.getLogger("sysLog");
    @Scheduled(cron = "0/20 * * * * ?")
    private void dispatch() {
        if (GlobalVariables.DISPATCHING_STRATEGY == 0) {
            if (!GlobalVariables.isDispatchingBegin) {
                return;
            }
            relationshipCache.clearRelationships();
            relationshipPost.clearRelationship();
            ArrayList<String> supplierIds = supplierCache.getCachedSuppliers();
            statisticsService.reCaculateAvgAnswerTime();
            statisticsService.incrSuccessDemandCount();
            statisticsService.addAvgAnswerTimeToAnswerTimeList();
            statisticsService.addSuccessRateToSuccessRateList();
            if (supplierIds.size() > 0) {
                for (String supplierId : supplierIds) {
                    try {
                        SupplierEndpoint.getSupplierSessions().get(supplierId).getBasicRemote().sendText("round_ended");
                    } catch (IOException e) {
                        sysLogger.info("failed");
                    }
                }
            }
            ArrayList<String> demandIds = demandCache.getCachedDemands();
            statisticsService.setRoundDemandNum(demandIds.size());
            if (supplierIds.size() == 0 || demandIds.size() == 0) {
                sysLogger.info("No dispatching at" + LocalDateTime.now());
                return;
            }
            float[][][] probabilitiesOneToOne = DispatchingMatrixTool.getProbabilities(demandIds, supplierIds);
            int[][] demandsSuppliersMatrix = new int[supplierIds.size()][demandIds.size()];
            demandsSuppliersMatrix = DispatchingMatrixTool.initDispatchMatrix(demandsSuppliersMatrix, probabilitiesOneToOne);
            demandsSuppliersMatrix = dispatchingService.dispatching(demandsSuppliersMatrix, probabilitiesOneToOne);
            HashMap<String, ArrayList<String>> manyToManyRelationship = new HashMap<>();
            HashMap<String, ArrayList<DemandDispatchingInfo>> dispatchingInfos = new HashMap<>();
            Map<String, Session> supplierSessions = SupplierEndpoint.getSupplierSessions();
            for (int supplierIndex = 0; supplierIndex < supplierIds.size(); supplierIndex++) {
                ArrayList<Integer> demandIndexes = DispatchingMatrixTool.getDemandIndexesBySupplierIndex(supplierIndex, demandsSuppliersMatrix);
                ArrayList<DemandDispatchingInfo> dispatchingInfo = new ArrayList<>(demandIndexes.size());
                ArrayList<String> receivedDemandIds = new ArrayList<>();
                for (Integer demandIndex : demandIndexes) {
                    DemandDispatchingInfo demandDispatchingInfo = new DemandDispatchingInfo();
                    demandDispatchingInfo.setId(demandIds.get(demandIndex));
                    receivedDemandIds.add(demandIds.get(demandIndex));
                    demandDispatchingInfo.setProbabilities(probabilitiesOneToOne[supplierIndex][demandIndex]);
                    dispatchingInfo.add(demandDispatchingInfo);
                    relationshipCache.addRelationship(demandIds.get(demandIndex) + "-" + supplierIds.get(supplierIndex));
                }
                manyToManyRelationship.put(supplierIds.get(supplierIndex), receivedDemandIds);
                dispatchingInfos.put(supplierIds.get(supplierIndex), dispatchingInfo);
            }
            relationshipPost.initRelationship(manyToManyRelationship);
            for (String supplierId : supplierIds) {
                try {
                    supplierSessions.get(supplierId).getBasicRemote().sendText(JSONObject.toJSONString(dispatchingInfos.get(supplierId)));
                } catch (IOException e) {
                    sysLogger.info(supplierId + " failed to receive demand info!");
                }
            }
        }
    }
}
